﻿using System.Linq;
using System;

namespace zTalk
{
    class UserManager
    {
        public static zTalkDataContext DB { get; set; }

        public static User Login(string username, string password)
        {
            User user = (from u in DB.Users
                         where u.Username == username && u.Password == password
                         select u).Single();
            user.Status = (int)UserStatus.ONLINE;
            DB.SubmitChanges();

            return user;
        }

        public static void Logout(string username)
        {
            User user = (from u in DB.Users
                        where u.Username == username
                        select u).Single();
            user.Status = (int)UserStatus.OFFLINE;
            DB.SubmitChanges();
        }

        public static void LogoutAll()
        {
            var users = from u in DB.Users
                        where u.Status != (int)UserStatus.OFFLINE
                        select u;

            foreach (var user in users)
            {
                user.Status = (int)UserStatus.OFFLINE;
            }

            DB.SubmitChanges();
        }

        public static void Register(string username, string password)
        {
            User user = new User();

            var x = (from u in DB.Users
                     where u.Username == username
                     select u).Count();
            if (x > 0)
            {
                throw new Exception("Username already exists");
            }
            user.Username = username;
            user.Password = password;
            DB.Users.InsertOnSubmit(user);

            DB.SubmitChanges();
        }

        public static UserProto[] GetFriends(int userId)
        {
            var friendIds = from f in DB.Friends
                            where f.UserID == userId
                            orderby f.FriendID
                            select f.FriendID;

            var friends = from u in DB.Users
                          where friendIds.Contains(u.UserID)
                          orderby u.Status descending
                          select new UserProto
                          {
                              Username = u.Username,
                              Status = (UserStatus)u.Status,
                              About = u.About,
                              Avatar = u.Avatar,
                          };

            return friends.ToArray();
        }

        public static User AddFriend(int userId, string friendname)
        {
            Friend friend = new Friend();

            friend.UserID = userId;
            friend.FriendID = GetUserId(friendname);
            DB.Friends.InsertOnSubmit(friend);

            DB.SubmitChanges();

            int friendId = GetUserId(friendname);
            return (from u in DB.Users
                    where u.UserID == friendId
                    select u).Single();
        }

        public static void RemoveFriend(int userId, string friendname)
        {
            var friend = (from f in DB.Friends
                          where f.FriendID == GetUserId(friendname) &&
                                f.UserID == userId
                          select f).Single();

            DB.Friends.DeleteOnSubmit(friend);
            DB.SubmitChanges();
        }

        public static int GetUserId(string username)
        {
            var user = (from u in DB.Users
                        where u.Username == username
                        select u).Single();

            return user.UserID;
        }

        public static void ChangeUser(int userId, UserProto changes)
        {
            var user = (from u in DB.Users
                        where u.UserID == userId
                        select u).Single();
            user.Status = (int)changes.Status;
            user.About = changes.About;
            DB.SubmitChanges();
        }

        public static UserProto[] GetNotifyFriends(int userId)
        {
            var notifyIds = from f in DB.Friends
                            where f.FriendID == userId
                            select f.UserID;

            var notifyUsers = from u in DB.Users
                              where notifyIds.Contains(u.UserID) &&
                                u.Status != (int)UserStatus.OFFLINE
                              select new UserProto
                              {
                                  Username = u.Username,
                                  Status = (UserStatus)u.Status,
                                  About = u.About
                              };

            return notifyUsers.ToArray();
        }

        public static void UpdateProfile(int userId, string about, string name, string email, int gender)
        {
            var user = (from u in DB.Users
                        where u.UserID == userId
                        select u).Single();

            user.About = about;
            user.Name = name;
            user.Email = email;
            user.Gender = gender;

            DB.SubmitChanges();
        }

        public static string[] GetProfile(string username)
        {
            int userId = GetUserId(username);
            var user = (from u in DB.Users
                        where u.UserID == userId
                        select new string[] {
                            u.About, u.Name, u.Email, u.Gender.ToString()
                        }).Single();

            return user;
        }

        public static void UpdatePassword(int userId, string oldpass, string newpass)
        {
            var user = (from u in DB.Users
                        where u.UserID == userId && u.Password == oldpass
                        select u).Single();
            user.Password = newpass;
            DB.SubmitChanges();
        }

        public static bool IsFriend(int userId, string friendname)
        {
            int friendId = GetUserId(friendname);

            var x = (from f in DB.Friends
                     where f.UserID == friendId && f.FriendID == userId
                     select f).Count();

            return (x != 0);
        }

        public static void SaveAvatar(int userId, string avatar64)
        {
            var user = (from u in DB.Users
                        where u.UserID == userId
                        select u).Single();
            user.Avatar = avatar64;
            DB.SubmitChanges();
        }

        public static UserProto GetUser(string username)
        {
            return (from u in DB.Users
                    where u.Username == username
                    select new UserProto
                    {
                        Username = u.Username,
                        Status = (UserStatus)u.Status,
                        About = u.About,
                        Avatar = u.Avatar
                    }
                    ).Single();
        }

        public static void AddMessage(MessageProto message)
        {
            Message msg = new Message
            {
                Source = message.Source,
                Destination = message.Destination,
                Text = message.Text,
                Time = message.Time,
            };
            DB.Messages.InsertOnSubmit(msg);
            DB.SubmitChanges();
        }

        public static MessageProto[] GetMessages(string username)
        {
            var messages = from message in DB.Messages
                    where message.Destination == username
                    select message;

            MessageProto[] result = (from m in messages
                                     select new MessageProto
                                     {
                                         Source = m.Source,
                                         Destination = m.Destination,
                                         Text = m.Text,
                                         Time = m.Time,
                                     }
                                     ).ToArray();

            DB.Messages.DeleteAllOnSubmit(messages);
            DB.SubmitChanges();

            return result;
        }
    }
}
